package Wallpaper::Execute::Themer;
$VERSION = sprintf "%.3f", 1 + substr(q$Revision: 159 $,9)/1000;

package Wallpaper::Execute;
use Storable qw( dclone );
use Wallpaper::Configuration qw( %datastore );

use Image::Magick;
use Color::Scheme;

use strict;

=item * getscheme

getscheme retrieves the Red, Green, and Blue Means.  It then combines these,
divides by three to determine if an image is bright or not.  It then makes some
choices about how to pick a scheme, finally creates one.

getscheme's last task is to launch conkytweak.

It accepts one parameter, a reference to the imagemagick object to inspect.  It
returns a hash of arrays which contain the selected scheme.

=cut

sub getscheme {
    my ( $self, $display, $image ) = @_;
    my ( $basecolor, $return, $saturation, %colorscheme, $currentscheme );
    undef $currentscheme;
    undef %colorscheme;

    my $general_config = Wallpaper::Configuration->general;
    my $debug          = $general_config->{ 'debug' };
    my $this_function  = ( caller( 0 ) )[3];

    print "$self : $this_function (2) Selecting a color palate to work with:\n" if ( $debug ge "2" );

    my $filename = $image->Get( 'filename' );    # Get the image filename (used later)

    # Returned = (for reference)
    # 0  - Red Depth
    # 1  - Red Minima
    # 2  - Red Maxima
    # 3  - Red Mean
    # 4  - Red Deviation
    # 5  - Blue Depth
    # 6  - Blue Minima
    # 7  - Blue Maxima
    # 8  - Blue Mean
    # 9  - Blue Deviation
    # 10 - Green Depth
    # 11 - Green Minima
    # 12 - Green Maxima
    # 13 - Green Mean
    # 14 - Green Deviation

    my @statistics = $image->Statistics();                                        # Retrieve the above stats
    my $red        = $statistics[3];
    my $green      = $statistics[8];
    my $blue       = $statistics[13];
    my $avg        = ( $statistics[3] + $statistics[8] + $statistics[13] ) / 3;

    # Some images return RGB colors in 16 bit instead of 254, so lets convert
    # them back into normal RGB values ( 0 - 254 ).

    if ( $avg > 254 ) {
        $red   = $red / 254;
        $green = $green / 254;
        $blue  = $blue / 254;
        $avg   = ( $red + $blue + $green ) / 3;
    }

    # Bash photo brightness values to workable levels
    while ( $avg > 128 ) {
        $red--;
        $green--;
        $blue--;
        $avg--;
        print "$self : $this_function (4) AHHH, my eyes are burning ... too white!, reducing mean by 1 : $red, $green, $blue, $avg\n"
          if ( $debug ge "4" );
    } ## end while ( $avg > 128 )
    while ( $avg < 128 ) {
        $red++;
        $green++;
        $blue++;
        $avg++;
        print "$self : $this_function (4) EEHH? Cant see it! ... too dark, increasing mean by 1 : $red, $green, $blue, $avg\n" if ( $debug ge "4" );
    }

    # Retrieve the HSV values of the mean colors grabbed above by imagemagick.
    my ( $hue, $saturation, $value ) = RGBtoHSV( $red, $green, $blue );

    # Make decisions about what to do with color based on saturation
    if ( $saturation < .1 ) {
        print "$self : $this_function (2) Saturation $saturation is low, using a preset\n" if ( $debug ge "2" );
        my $index = rand scalar @{ $general_config->{ 'schema_preset' } };    # schemapreset;
        $basecolor = $general_config->{ 'schema_preset' }[$index];
    } else {
        ( $red, $green, $blue ) = HSVtoRGB( $hue, '.5', $value );
        print "$self : $this_function (2) Saturation $saturation set to .5\n" if ( $debug ge "2" );
    }

    # Image Preset Overrides if RGB color is embedded in filename, even if it
    # violates the above saturation filter!

    if ( $filename =~ /_#/ ) {
        ( $basecolor ) = $filename =~ /_#(.*)_/;
        print "$self : $this_function (2) Preset Override with $basecolor!\n" if ( $debug ge "2" );
        $avg = 1;    # Bypass tests
    }

    print "$self : $this_function (3) Red Mean: $red\n"     if ( $debug ge "3" );
    print "$self : $this_function (3) Green Mean: $green\n" if ( $debug ge "3" );
    print "$self : $this_function (3) Blue Mean: $blue\n"   if ( $debug ge "3" );
    print "$self : $this_function (3) Avg Mean: $avg\n"     if ( $debug ge "3" );

    # Set border basecolor only if $basecolor has not allready been defined
    # above

    if ( !$basecolor ) {
        $basecolor = sprintf( "%02X%02X%02X\n", $red, $green, $blue );    # Convert Base 256 rgb color mean to base16 (hex)
    }
    print "$self : $this_function (3) Selected Base color of image is $basecolor\n" if ( $debug ge "3" );

    # Now create our color scheme.
    $currentscheme                                  = makescheme( $basecolor );
    $datastore{ $display }{ 'scheme' }{ 'primary' } = hashcolors( $currentscheme->[0] );
    $datastore{ $display }{ 'scheme' }{ 'warm' }    = hashcolors( $currentscheme->[1] );
    $datastore{ $display }{ 'scheme' }{ 'cool' }    = hashcolors( $currentscheme->[1] );
    $datastore{ $display }{ 'scheme' }{ 'comp' }    = hashcolors( $currentscheme->[1] );

    $currentscheme                                    = makescheme( $datastore{ $display }{ 'scheme' }{ 'warm' }{ 'base' } );
    $datastore{ $display }{ 'scheme' }{ 'warmer' }    = hashcolors( $currentscheme->[1] );
    $datastore{ $display }{ 'scheme' }{ 'comp_warm' } = hashcolors( $currentscheme->[3] );

    $currentscheme                                      = makescheme( $datastore{ $display }{ 'scheme' }{ 'warmer' }{ 'base' } );
    $datastore{ $display }{ 'scheme' }{ 'warmest' }     = hashcolors( $currentscheme->[1] );
    $datastore{ $display }{ 'scheme' }{ 'comp_warmer' } = hashcolors( $currentscheme->[3] );

    $currentscheme                                    = makescheme( $datastore{ $display }{ 'scheme' }{ 'cool' }{ 'base' } );
    $datastore{ $display }{ 'scheme' }{ 'cooler' }    = hashcolors( $currentscheme->[2] );
    $datastore{ $display }{ 'scheme' }{ 'comp_cool' } = hashcolors( $currentscheme->[3] );

    $currentscheme                                      = makescheme( $datastore{ $display }{ 'scheme' }{ 'cooler' }{ 'base' } );
    $datastore{ $display }{ 'scheme' }{ 'coolest' }     = hashcolors( $currentscheme->[2] );
    $datastore{ $display }{ 'scheme' }{ 'comp_cooler' } = hashcolors( $currentscheme->[3] );

    #open( OUTPUT, ">" . "/dev/shm/walls/scheme-$display" );

    #my @schemetype  = qw( primary warm warmer warmest cool cooler coolest comp comp_warm comp_warmer comp_cool comp_cooler );
    #my @schemeitems = qw( base dark pale lpale );
    #for my $types ( @schemetype ) {
    #    for my $color ( @schemeitems ) {
    #        print OUTPUT "$datastore{$display}{'scheme'}{$types}{$color} ";
    #    }
    #}
    #close OUTPUT;

  return $datastore{ $display }{ 'scheme' };

    exit( 0 );

    sub makescheme {
        my ( $initcolor ) = @_;
        my $scheme = Color::Scheme->new;

        $scheme->from_hex( $initcolor );
        $scheme->scheme( 'analogic' );
        $scheme->add_complement( 1 );
        $scheme->distance( 0.4 );    # .25 = 15 degrees and .50 = 30 degrees on the colorwheel

      return $scheme->colorset;
    } ## end sub makescheme

    sub hashcolors {
        my ( $array ) = @_;
        my %self;

        $self{ 'base' }  = $array->[0];
        $self{ 'dark' }  = $array->[1];
        $self{ 'pale' }  = $array->[2];
        $self{ 'lpale' } = $array->[3];

      return \%self;

    } ## end sub hashcolors

    # The following code was ripped rather mercilessly from
    # Graphics::RGBManipulate by Pete Sergeant - pete@clueball.com

    # Round a number
    sub round {
        my $number  = $_[0];
        my $integer = int( $number );
      return $integer if ( $integer + 0.5 > $number );
      return ++$integer;
    }

    # Return the smallest value from a list
    sub min {
        my @values = sort { $a <=> $b } ( @_ );
      return shift @values;
    }

    # Return the largest value from a list
    sub max {
        my @values = sort { $a <=> $b } ( @_ );
      return pop @values;
    }

    # Accepts a list with three elements, integers between 0 and 255
    sub RGBtoHSV {

        my ( $red, $green, $blue ) = @_;
        my ( $hue, $saturation, $v );

        my $min = min( $red, $green, $blue );
        my $max = max( $red, $green, $blue );

        # The value is the highest of the RGB values
        my $v = $max;

        my $delta = $max - $min;

        # If we have a colour (thus aren't grey), then work out the saturation
        if ( $delta ) {
            $saturation = $delta / $max;

            # We're a grey, so do the right thing
        } else {
            $saturation = 0;
            $hue        = 0;
          return ( $hue, $saturation, $v );
        }

        # How we calculate hue depends on which was the largest RGB value
        if ( $red == $max ) {
            $hue = ( $green - $blue ) / $delta;
        } elsif ( $green == $max ) {
            $hue = 2 + ( $blue - $red ) / $delta;
        } else {
            $hue = 4 + ( $red - $green ) / $delta;
        }

        # Change hue to degrees on the colour wheel
        $hue *= 60;

        # Make sure hue is a positive number
        $hue += 360 if ( $hue < 0 );

      return ( $hue, $saturation, $v );

    } ## end sub RGBtoHSV

    # Accepts a list of three values: hue is 0 to 360, saturation is 0 to 1, and value is 0 to 255
    sub HSVtoRGB {

        my ( $hue, $saturation, $v ) = @_;
        my ( $red, $green, $blue );

        # If there's no saturation, then we're a grey
        unless ( $saturation ) {
            $red = $green = $blue = $v;
          return ( $red, $green, $blue );
        }

        $hue /= 60;
        my $i = int( $hue );
        my $f = $hue - $i;
        my $p = $v * ( 1 - $saturation );
        my $q = $v * ( 1 - $saturation * $f );
        my $t = $v * ( 1 - $saturation * ( 1 - $f ) );

        if    ( $i == 0 ) { return ( $v, $t, $p ) }
        elsif ( $i == 1 ) { return ( $q, $v, $p ) }
        elsif ( $i == 2 ) { return ( $p, $v, $t ) }
        elsif ( $i == 3 ) { return ( $p, $q, $v ) }
        elsif ( $i == 4 ) { return ( $t, $p, $v ) }
        else              { return ( $v, $p, $q ) }

    } ## end sub HSVtoRGB

} ## end sub getscheme

package Color::Scheme;

sub DESTROY {
    my $self = shift;
    undef $self;
}

1;
